home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / ip / nfs / nfswatch4.0 / rpcfilter.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-01  |  19.5 KB  |  884 lines

  1. #ifndef lint
  2. static char *RCSid = "$Header: /home/harbor/davy/system/nfswatch/RCS/rpcfilter.c,v 4.0 1993/03/01 19:59:00 davy Exp $";
  3. #endif
  4.  
  5. #include "os.h"
  6.  
  7. /*
  8.  * rpcfilter.c - filter RPC packets.
  9.  *
  10.  * David A. Curry                Jeffrey C. Mogul
  11.  * Purdue University                Digital Equipment Corporation
  12.  * Engineering Computer Network            Western Research Laboratory
  13.  * 1285 Electrical Engineering Building        250 University Avenue
  14.  * West Lafayette, IN 47907-1285        Palo Alto, CA 94301
  15.  * davy@ecn.purdue.edu                mogul@decwrl.dec.com
  16.  *
  17.  * $Log: rpcfilter.c,v $
  18.  * Revision 4.0  1993/03/01  19:59:00  davy
  19.  * NFSWATCH Version 4.0.
  20.  *
  21.  * Revision 3.7  1993/03/01  19:57:23  davy
  22.  * Fixed some byte-order bugs.
  23.  *
  24.  * Revision 3.6  1993/02/24  17:44:45  davy
  25.  * Added -auth mode, changes to -proc mode, -map option, -server option.
  26.  *
  27.  * Revision 3.5  1993/01/16  19:08:59  davy
  28.  * Corrected Jeff's address.
  29.  *
  30.  * Revision 3.4  1993/01/15  19:33:39  davy
  31.  * Miscellaneous cleanups.
  32.  *
  33.  * Revision 3.3  1993/01/15  15:43:36  davy
  34.  * Assorted changes for porting to Solaris 2.x/SVR4.
  35.  *
  36.  * Revision 3.2  1993/01/13  20:18:17  davy
  37.  * Put in OS-specific define scheme, and merged in Tim Hudson's code for
  38.  * SGI systems (as yet untested).
  39.  *
  40.  * Revision 3.1  1993/01/13  13:50:59  davy
  41.  * Made the file matching code work on Sun-3's, and also put a generic one in
  42.  * there in hopes it'll work.
  43.  *
  44.  * Revision 3.0  1991/01/23  08:23:20  davy
  45.  * NFSWATCH Version 3.0.
  46.  *
  47.  * Revision 1.5  91/01/17  10:13:02  davy
  48.  * Bug fix from Jeff Mogul.
  49.  * 
  50.  * Revision 1.7  91/01/16  15:49:12  mogul
  51.  * Print server or client address in a.b.c.d notation if name not known
  52.  * 
  53.  * Revision 1.6  91/01/07  15:35:51  mogul
  54.  * Uses hash table instead of linear search on clients
  55.  * One-element "hint" cache to avoid client hash lookup
  56.  * 
  57.  * Revision 1.5  91/01/04  14:12:35  mogul
  58.  * Support for client counters
  59.  * Disable screen update during database upheaval
  60.  * 
  61.  * Revision 1.4  91/01/03  17:35:00  mogul
  62.  * Count per-procedure info
  63.  * 
  64.  * Revision 1.3  90/12/04  08:22:06  davy
  65.  * Fix from Dan Trinkle (trinkle@cs.purdue.edu) to determine byte order in
  66.  * file handle.
  67.  * 
  68.  * Revision 1.2  90/08/17  15:47:44  davy
  69.  * NFSWATCH Version 2.0.
  70.  * 
  71.  * Revision 1.1  88/11/29  11:20:51  davy
  72.  * NFSWATCH Release 1.0
  73.  * 
  74.  */
  75. #include <sys/param.h>
  76. #include <sys/socket.h>
  77. #include <netinet/in.h>
  78. #include <sys/stat.h>
  79. #ifdef SVR4
  80. #include <sys/tiuser.h>
  81. #include <sys/sysmacros.h>
  82. #endif
  83. #include <rpc/types.h>
  84. #include <rpc/xdr.h>
  85. #include <rpc/auth.h>
  86. #include <rpc/clnt.h>
  87. #include <rpc/rpc_msg.h>
  88. #include <rpc/pmap_clnt.h>
  89. #include <rpc/svc.h>
  90. #include <netdb.h>
  91. #include <errno.h>
  92. #include <stdio.h>
  93. #include <signal.h>
  94. #include <math.h>
  95. #include <pwd.h>
  96.  
  97. #define NFSSERVER    1
  98.  
  99. #ifdef sun
  100. #include <sys/vfs.h>
  101. #include <nfs/nfs.h>
  102. #endif
  103. #ifdef ultrix
  104. #include <sys/types.h>
  105. #include <sys/time.h>
  106. #include <nfs/nfs.h>
  107. #endif
  108. #ifdef sgi
  109. #include <sys/time.h>
  110. #include "sgi.map.h"
  111. #include <sys/sysmacros.h>
  112. #endif
  113.  
  114. #include "nfswatch.h"
  115. #include "externs.h"
  116. #include "rpcdefs.h"
  117.  
  118. /*
  119.  * NFS procedure types and XDR argument decoding routines.
  120.  */
  121. static struct nfs_proc nfs_procs[] = {
  122. /* RFS_NULL (0)        */
  123.     NFS_READ,    xdr_void,    0,
  124. /* RFS_GETATTR (1)    */
  125.     NFS_READ,    xdr_fhandle,    sizeof(fhandle_t),
  126. /* RFS_SETATTR (2)    */
  127.     NFS_WRITE,    xdr_saargs,    sizeof(struct nfssaargs),
  128. /* RFS_ROOT (3)        */
  129.     NFS_READ,    xdr_void,    0,
  130. /* RFS_LOOKUP (4)    */
  131.     NFS_READ,    xdr_diropargs,    sizeof(struct nfsdiropargs),
  132. /* RFS_READLINK (5)    */
  133.     NFS_READ,    xdr_fhandle,    sizeof(fhandle_t),
  134. /* RFS_READ (6)        */
  135.     NFS_READ,    xdr_readargs,    sizeof(struct nfsreadargs),
  136. /* RFS_WRITECACHE (7)    */
  137.     NFS_WRITE,    xdr_void,    0,
  138. /* RFS_WRITE (8)    */
  139.     NFS_WRITE,    xdr_writeargs,    sizeof(struct nfswriteargs),
  140. /* RFS_CREATE (9)    */
  141.     NFS_WRITE,    xdr_creatargs,    sizeof(struct nfscreatargs),
  142. /* RFS_REMOVE (10)    */
  143.     NFS_WRITE,    xdr_diropargs,    sizeof(struct nfsdiropargs),
  144. /* RFS_RENAME (11)    */
  145.     NFS_WRITE,    xdr_rnmargs,    sizeof(struct nfsrnmargs),
  146. /* RFS_LINK (12)    */
  147.     NFS_WRITE,    xdr_linkargs,    sizeof(struct nfslinkargs),
  148. /* RFS_SYMLINK (13)    */
  149.     NFS_WRITE,    xdr_slargs,    sizeof(struct nfsslargs),
  150. /* RFS_MKDIR (14)    */
  151.     NFS_WRITE,    xdr_creatargs,    sizeof(struct nfscreatargs),
  152. /* RFS_RMDIR (15)    */
  153.     NFS_WRITE,    xdr_diropargs,    sizeof(struct nfsdiropargs),
  154. /* RFS_READDIR (16)    */
  155.     NFS_READ,    xdr_rddirargs,    sizeof(struct nfsrddirargs),
  156. /* RFS_STATFS (17)    */
  157.     NFS_READ,    xdr_fhandle,    sizeof(fhandle_t)
  158. };
  159.  
  160. NFSCall nfs_calls[NFSCALLHASHSIZE];
  161.  
  162. /*
  163.  * rpc_filter - pass off RPC packets to other filters.
  164.  */
  165. void
  166. rpc_filter(data, length, src, dst, tstamp)
  167. register u_long src, dst;
  168. struct timeval *tstamp;
  169. register u_int length;
  170. register char *data;
  171. {
  172.     register struct rpc_msg *msg;
  173.  
  174.     msg = (struct rpc_msg *) data;
  175.  
  176.     /*
  177.      * See which "direction" the packet is going.  We
  178.      * can classify RPC CALLs, but we cannot classify
  179.      * REPLYs, since they no longer have the RPC
  180.      * program number in them (sigh).
  181.      */
  182.     switch (ntohl(msg->rm_direction)) {
  183.     case CALL:            /* RPC call            */
  184.         rpc_callfilter(data, length, src, dst, tstamp);
  185.         break;
  186.     case REPLY:            /* RPC reply            */
  187.         rpc_replyfilter(data, length, src, dst, tstamp);
  188.         break;
  189.     default:            /* probably not an RPC packet    */
  190.         break;
  191.     }
  192. }
  193.  
  194. /*
  195.  * rpc_callfilter - filter RPC call packets.
  196.  */
  197. void
  198. rpc_callfilter(data, length, src, dst, tstamp)
  199. register u_long src, dst;
  200. struct timeval *tstamp;
  201. register u_int length;
  202. register char *data;
  203. {
  204.     register struct rpc_msg *msg;
  205.  
  206.     msg = (struct rpc_msg *) data;
  207.  
  208.     /*
  209.      * Decide what to do based on the program.
  210.      */
  211.     switch (ntohl(msg->rm_call.cb_prog)) {
  212.     case RPC_NFSPROG:
  213.         nfs_filter(data, length, src, dst, tstamp);
  214.         break;
  215.     case RPC_YPPROG:
  216.     case RPC_YPBINDPROG:
  217.     case RPC_YPPASSWDPROG:
  218.     case RPC_YPUPDATEPROG:
  219.     case RPC_CACHEPROG:
  220.     case RPC_CB_PROG:
  221.         pkt_counters[PKT_YELLOWPAGES].pc_interval++;
  222.         pkt_counters[PKT_YELLOWPAGES].pc_total++;
  223.         break;
  224.     case RPC_MOUNTPROG:
  225.         pkt_counters[PKT_NFSMOUNT].pc_interval++;
  226.         pkt_counters[PKT_NFSMOUNT].pc_total++;
  227.         break;
  228. #ifdef notdef
  229.     case RPC_PMAPPROG:
  230.     case RPC_RSTATPROG:
  231.     case RPC_RUSERSPROG:
  232.     case RPC_DBXPROG:
  233.     case RPC_WALLPROG:
  234.     case RPC_ETHERSTATPROG:
  235.     case RPC_RQUOTAPROG:
  236.     case RPC_SPRAYPROG:
  237.     case RPC_IBM3270PROG:
  238.     case RPC_IBMRJEPROG:
  239.     case RPC_SELNSVCPROG:
  240.     case RPC_RDATABASEPROG:
  241.     case RPC_REXECPROG:
  242.     case RPC_ALICEPROG:
  243.     case RPC_SCHEDPROG:
  244.     case RPC_LOCKPROG:
  245.     case RPC_NETLOCKPROG:
  246.     case RPC_X25PROG:
  247.     case RPC_STATMON1PROG:
  248.     case RPC_STATMON2PROG:
  249.     case RPC_SELNLIBPROG:
  250.     case RPC_BOOTPARAMPROG:
  251.     case RPC_MAZEPROG:
  252.     case RPC_KEYSERVEPROG:
  253.     case RPC_SECURECMDPROG:
  254.     case RPC_NETFWDIPROG:
  255.     case RPC_NETFWDTPROG:
  256.     case RPC_SUNLINKMAP_PROG:
  257.     case RPC_NETMONPROG:
  258.     case RPC_DBASEPROG:
  259.     case RPC_PWDAUTHPROG:
  260.     case RPC_TFSPROG:
  261.     case RPC_NSEPROG:
  262.     case RPC_NSE_ACTIVATE_PROG:
  263.     case RPC_PCNFSDPROG:
  264.     case RPC_PYRAMIDLOCKINGPROG:
  265.     case RPC_PYRAMIDSYS5:
  266.     case RPC_CADDS_IMAGE:
  267.     case RPC_ADT_RFLOCKPROG:
  268. #endif
  269.     default:
  270.         pkt_counters[PKT_OTHERRPC].pc_interval++;
  271.         pkt_counters[PKT_OTHERRPC].pc_total++;
  272.         break;
  273.     }
  274. }
  275.  
  276. /*
  277.  * rpc_replyfilter - count RPC reply packets.
  278.  */
  279. void
  280. rpc_replyfilter(data, length, src, dst, tstamp)
  281. register u_long src, dst;
  282. struct timeval *tstamp;
  283. register u_int length;
  284. register char *data;
  285. {
  286.     register struct rpc_msg *msg;
  287.  
  288.     msg = (struct rpc_msg *) data;
  289.  
  290.     pkt_counters[PKT_RPCAUTH].pc_interval++;
  291.     pkt_counters[PKT_RPCAUTH].pc_total++;
  292.     nfs_hash_reply(msg, dst, tstamp);
  293. }
  294.  
  295. /*
  296.  * nfs_filter - filter NFS packets.
  297.  */
  298. void
  299. nfs_filter(data, length, src, dst, tstamp)
  300. register u_long src, dst;
  301. struct timeval *tstamp;
  302. register u_int length;
  303. register char *data;
  304. {
  305.     u_int proc;
  306.     caddr_t args;
  307.     SVCXPRT *xprt;
  308.     struct rpc_msg msg;
  309.     union nfs_rfsargs nfs_rfsargs;
  310.     char cred_area[2*MAX_AUTH_BYTES];
  311.  
  312.     msg.rm_call.cb_cred.oa_base = cred_area;
  313.     msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
  314.  
  315.     /*
  316.      * Act as if we received this packet through RPC.
  317.      */
  318.     if (!udprpc_recv(data, length, &msg, &xprt))
  319.         return;
  320.  
  321.     /*
  322.      * Get the NFS procedure number.
  323.      */
  324.     proc = msg.rm_call.cb_proc;
  325.  
  326.     if (proc >= RFS_NPROC)
  327.         return;
  328.  
  329.     CountCallAuth(&msg);
  330.     nfs_hash_call(&msg, src, tstamp);
  331.  
  332.     /*
  333.      * Now decode the arguments to the procedure from
  334.      * XDR format.
  335.      */
  336.     args = (caddr_t) &nfs_rfsargs;
  337.     (void) bzero(args, nfs_procs[proc].nfs_argsz);
  338.  
  339.     if (!SVC_GETARGS(xprt, nfs_procs[proc].nfs_xdrargs, args))
  340.         return;
  341.  
  342.     prc_counters[prc_countmap[proc]].pr_total++;
  343.     prc_counters[prc_countmap[proc]].pr_interval++;
  344.  
  345.     CountSrc(src);
  346.  
  347.     /*
  348.      * Now count the packet in the appropriate file system's
  349.      * counters.
  350.      */
  351.     switch (proc) {
  352.     case RFS_NULL:
  353.         break;
  354.     case RFS_GETATTR:
  355.         nfs_count(&nfs_rfsargs.fhandle, proc);
  356.         break;
  357.     case RFS_SETATTR:
  358.         nfs_count(&nfs_rfsargs.nfssaargs.saa_fh, proc);
  359.         break;
  360.     case RFS_ROOT:
  361.         break;
  362.     case RFS_LOOKUP:
  363.         nfs_count(&nfs_rfsargs.nfsdiropargs.da_fhandle, proc);
  364.         break;
  365.     case RFS_READLINK:
  366.         nfs_count(&nfs_rfsargs.fhandle, proc);
  367.         break;
  368.     case RFS_READ:
  369.         nfs_count(&nfs_rfsargs.nfsreadargs.ra_fhandle, proc);
  370.         break;
  371.     case RFS_WRITECACHE:
  372.         break;
  373.     case RFS_WRITE:
  374.         nfs_count(&nfs_rfsargs.nfswriteargs.wa_fhandle, proc);
  375.         break;
  376.     case RFS_CREATE:
  377.         nfs_count(&nfs_rfsargs.nfscreatargs.ca_da.da_fhandle, proc);
  378.         break;
  379.     case RFS_REMOVE:
  380.         nfs_count(&nfs_rfsargs.nfsdiropargs.da_fhandle, proc);
  381.         break;
  382.     case RFS_RENAME:
  383.         nfs_count(&nfs_rfsargs.nfsrnmargs.rna_from.da_fhandle, proc);
  384.         break;
  385.     case RFS_LINK:
  386.         nfs_count(&nfs_rfsargs.nfslinkargs.la_from, proc);
  387.         break;
  388.     case RFS_SYMLINK:
  389.         nfs_count(&nfs_rfsargs.nfsslargs.sla_from.da_fhandle, proc);
  390.         break;
  391.     case RFS_MKDIR:
  392.         nfs_count(&nfs_rfsargs.nfscreatargs.ca_da.da_fhandle, proc);
  393.         break;
  394.     case RFS_RMDIR:
  395.         nfs_count(&nfs_rfsargs.nfsdiropargs.da_fhandle, proc);
  396.         break;
  397.     case RFS_READDIR:
  398.         nfs_count(&nfs_rfsargs.nfsrddirargs.rda_fh, proc);
  399.         break;
  400.     case RFS_STATFS:
  401.         nfs_count(&nfs_rfsargs.fhandle, proc);
  402.         break;
  403.     }
  404.  
  405.     /*
  406.      * Decide whether it's a read or write process.
  407.      */
  408.     switch (nfs_procs[proc].nfs_proctype) {
  409.     case NFS_READ:
  410.         pkt_counters[PKT_NFSREAD].pc_interval++;
  411.         pkt_counters[PKT_NFSREAD].pc_total++;
  412.         break;
  413.     case NFS_WRITE:
  414.         pkt_counters[PKT_NFSWRITE].pc_interval++;
  415.         pkt_counters[PKT_NFSWRITE].pc_total++;
  416.         break;
  417.     }
  418. }
  419.  
  420. /*
  421.  * nfs_count - count an NFS reference to a specific file system.
  422.  */
  423. void
  424. nfs_count(fh, proc)
  425. register fhandle_t *fh;
  426. int proc;
  427. {
  428.     long fsid;
  429.     register int i, match1, match2;
  430.  
  431.     /*
  432.      * Run through the NFS counters looking for the matching
  433.      * file system.
  434.      */
  435.     match1 = 0;
  436.  
  437.     for (i = 0; i < nnfscounters; i++) {
  438.         if (learnfs)
  439.             fsid = nfs_counters[i].nc_fsid;
  440.         else
  441.             fsid = (long) nfs_counters[i].nc_dev;
  442.  
  443.         /*
  444.          * Compare the device numbers.  Sun uses an
  445.          * fsid_t for the device number, which is an
  446.          * array of 2 longs.  The first long contains
  447.          * the device number.
  448.          */
  449.         match1 = !bcmp((char *) &(fh->fh_fsid), (char *) &fsid,
  450.             sizeof(long));
  451.  
  452.         /*
  453.          * Check server address.
  454.          */
  455.         if (allflag && match1)
  456.             match1 = (thisdst == nfs_counters[i].nc_ipaddr);
  457.  
  458.         if (match1) {
  459.             nfs_counters[i].nc_proc[proc]++;
  460.             nfs_counters[i].nc_interval++;
  461.             nfs_counters[i].nc_total++;
  462.             break;
  463.         }
  464.     }
  465.  
  466.     /*
  467.      * We don't know about this file system, but we can
  468.      * learn.
  469.      */
  470.     if (!match1 && learnfs && (nnfscounters < MAXEXPORT)) {
  471.         static char fsname[64], prefix[64];
  472.         long fsid;
  473.         int oldm;
  474.  
  475. #ifdef SVR4
  476.         sighold(SIGALRM);
  477. #else
  478.         oldm = sigblock(sigmask(SIGALRM));
  479. #endif
  480.                         /* no redisplay while unstable */
  481.  
  482.         i = nnfscounters++;
  483.  
  484.         bcopy((char *) &(fh->fh_fsid), (char *) &fsid, sizeof(long));
  485.  
  486.         nfs_counters[i].nc_fsid = fsid;
  487.         nfs_counters[i].nc_proc[proc]++;
  488.         nfs_counters[i].nc_interval++;
  489.         nfs_counters[i].nc_total++;
  490.  
  491.         /*
  492.          * See if server uses opposite byte order.
  493.          */
  494.         if ((fsid & 0xffff0000) && ((fsid & 0xffff) == 0))
  495.             fsid = ntohl(fsid);
  496.  
  497.         /*
  498.          * Some hosts use 32-bit values.
  499.          */
  500.         if (fsid & 0xffff0000) {
  501.             /*
  502.              * Try to intuit the byte order.
  503.              */
  504.             if (fsid & 0xff00) {
  505.               nfs_counters[i].nc_dev = makedev((fsid >> 8) & 0xff,
  506.                                (fsid >> 24) & 0xff);
  507.             }
  508.             else {
  509.               nfs_counters[i].nc_dev = makedev((fsid >> 16) & 0xff,
  510.                                fsid & 0xff);
  511.             }
  512.         }
  513.         else {
  514.             nfs_counters[i].nc_dev = makedev(major(fsid),
  515.                              minor(fsid));
  516.         }
  517.  
  518.         *prefix = 0;
  519.  
  520.         if (allflag) {
  521.             struct hostent *hp;
  522.  
  523.             nfs_counters[i].nc_ipaddr = thisdst;
  524.             hp = gethostbyaddr((char *) &thisdst, sizeof(thisdst),
  525.                        AF_INET);
  526.  
  527.             if (hp) {
  528.                 char *index();
  529.                 char *dotp;
  530.  
  531.                 sprintf(prefix, "%s", hp->h_name);
  532.  
  533.                 if ((dotp = index(prefix, '.')) != NULL)
  534.                     *dotp = 0;
  535.             }
  536.             else {
  537.                 struct in_addr ia;
  538.                 ia.s_addr = thisdst;
  539.                 sprintf(prefix, "%s", inet_ntoa(ia));
  540.             }
  541.         }
  542.  
  543.         sprintf(fsname, "%.12s(%d,%d)", prefix,
  544.             major(nfs_counters[i].nc_dev),
  545.             minor(nfs_counters[i].nc_dev));
  546.  
  547.         if (mapfile)
  548.             nfs_counters[i].nc_name = savestr(map_fs_name(fsname));
  549.         else
  550.             nfs_counters[i].nc_name = savestr(fsname);
  551.  
  552.         sort_nfs_counters();
  553. #ifdef SVR4
  554.         sigrelse(SIGALRM);
  555. #else
  556.         (void) sigsetmask(oldm);    /* permit redisplay */
  557. #endif
  558.     }
  559.  
  560.     if (filelist == NULL)
  561.         return;
  562.  
  563.     /*
  564.      * Run through the file counters looking for the matching
  565.      * file.
  566.      */
  567.     for (i = 0; i < nfilecounters; i++) {
  568.         fsid = (long) fil_counters[i].fc_dev;
  569.  
  570.         /*
  571.          * Compare device numbers and file numbers.  Sun
  572.          * uses an fsid_t for the device, which is an
  573.          * array of two longs.  They use an fid for the
  574.          * inode.  The inode number is the first part
  575.          * of this.
  576.          */
  577.         match1 = !bcmp((char *) &(fh->fh_fsid), (char *) &fsid,
  578.              sizeof(long));
  579.  
  580.         if (!match1)
  581.             continue;
  582.  
  583. #if defined(sun) && defined(sparc)
  584.         /*
  585.          * NOTE: this is dependent on the contents of the fh_data
  586.          *       part of the file handle.  This is correct for
  587.          *       SunOS 4.1 on SPARCs.
  588.          */
  589.         match2 = !bcmp((char *) &(fh->fh_data[2]),
  590.              (char *) &(fil_counters[i].fc_ino), sizeof(ino_t));
  591. #endif
  592.  
  593. #if defined(sun) && defined(mc68000)
  594.         /*
  595.          * Correct for SunOS 4.1 on Sun-3.
  596.          */
  597.         match2 = !bcmp((char *) &(fh->fh_data[0]),
  598.              (char *) &(fil_counters[i].fc_ino), sizeof(ino_t));
  599. #endif
  600.  
  601. #ifdef ultrix
  602.         /*
  603.          * Correct for Ultrix 4.x systems.
  604.          */
  605.         match2 = !bcmp((char *) fh->fh_fno,
  606.              (char *) &(fil_counters[i].fc_ino), sizeof(ino_t));
  607. #endif
  608.  
  609. #ifdef sgi
  610.         /*
  611.          * Correct for IRIX 3.3.
  612.          */
  613.         match2 = !bcmp((char *) &(fh->fh_data[4]),
  614.              (char *) &(fil_counters[i].fc_ino), sizeof(ino_t));
  615. #endif
  616.  
  617. #if !defined(sgi) && !defined(sun) && !defined(ultrix) 
  618.         /*
  619.          * This is a guess... it's probably correct for most
  620.          * SVR4 PC systems, anyway.
  621.          */
  622.         match2 = !bcmp((char *) &(fh->fh_data[0]),
  623.              (char *) &(fil_counters[i].fc_ino), sizeof(ino_t));
  624. #endif
  625.         
  626.         if (match2) {
  627.             fil_counters[i].fc_proc[proc]++;
  628.             fil_counters[i].fc_interval++;
  629.             fil_counters[i].fc_total++;
  630.             break;
  631.         }
  632.     }
  633. }
  634.  
  635. /*
  636.  * CountSrc uses a hash table to speed lookups.  Hash function
  637.  *    uses high and low octect of IP address, so as to be
  638.  *    fast and byte-order independent.  Table is organized
  639.  *    as a array of linked lists.
  640.  */
  641. #define    HASHSIZE    0x100
  642. #define    HASH(addr)    (((addr) & 0xFF) ^ (((addr) >> 24) & 0xFF))
  643.  
  644. ClientCounter *Addr_hashtable[HASHSIZE];    /* initially all NULL ptrs */
  645.  
  646. ClientCounter *cc_hint = clnt_counters;        /* one-element cache */
  647.  
  648. CountSrc(src)
  649. register u_long src;
  650. {
  651.     register ClientCounter *ccp;
  652.     int hcode = HASH(src);
  653.     
  654.     /* See if this is the same client as last time */
  655.     if (cc_hint->cl_ipaddr == src) {
  656.         cc_hint->cl_total++;
  657.         cc_hint->cl_interval++;
  658.         return;
  659.     }
  660.  
  661.     /* Search hash table */
  662.     ccp = Addr_hashtable[hcode];
  663.     while (ccp) {
  664.         if (ccp->cl_ipaddr == src) {
  665.         ccp->cl_total++;
  666.         ccp->cl_interval++;
  667.         cc_hint = ccp;
  668.         return;
  669.         }
  670.         ccp = ccp->cl_next;
  671.     }
  672.     
  673.     /* new client */
  674.     if (nclientcounters < MAXCLIENTS) {
  675.         struct hostent *hp;
  676.         static char clnt_name[64];
  677.         int oldm;
  678.         
  679. #ifdef SVR4
  680.         sighold(SIGALRM);
  681. #else
  682.         oldm = sigblock(sigmask(SIGALRM));
  683. #endif
  684.                         /* no redisplay while unstable */
  685.         
  686.         ccp = &(clnt_counters[nclientcounters]);
  687.         nclientcounters++;
  688.         
  689.         /* Add to hash table */
  690.         ccp->cl_next = Addr_hashtable[hcode];
  691.         Addr_hashtable[hcode] = ccp;
  692.  
  693.         /* Fill in new ClientCounter */
  694.         ccp->cl_ipaddr = src;
  695.         hp = gethostbyaddr((char *) &ccp->cl_ipaddr,
  696.                    sizeof(ccp->cl_ipaddr), AF_INET);
  697.         if (hp) {
  698.         char *index();
  699.         char *dotp;
  700.  
  701.         sprintf(clnt_name, "%s", hp->h_name);
  702.  
  703.         if ((dotp = index(clnt_name, '.')) != NULL)
  704.             *dotp = 0;
  705.         }
  706.         else {
  707.         struct in_addr ia;
  708.         ia.s_addr = ccp->cl_ipaddr;
  709.         sprintf(clnt_name, "%s", inet_ntoa(ia));
  710.         }
  711.  
  712.         ccp->cl_name = savestr(clnt_name);
  713.         ccp->cl_total = 1;
  714.         ccp->cl_interval = 1;
  715.         sort_clnt_counters();
  716. #ifdef SVR4
  717.          sigrelse(SIGALRM);
  718. #else
  719.         (void) sigsetmask(oldm);    /* permit redisplay */
  720. #endif
  721.     }
  722. }
  723.  
  724. /*
  725.  * Must be called after sorting the clnt_counters[] table
  726.  *    Should put busiest ones at front of list, but doesn't
  727.  */
  728. ClientHashRebuild()
  729. {
  730.     register int i;
  731.     register ClientCounter *ccp;
  732.     int hcode;
  733.  
  734.     bzero(Addr_hashtable, sizeof(Addr_hashtable));
  735.     
  736.     for (i = 0, ccp = clnt_counters; i < nclientcounters; i++, ccp++) {
  737.         hcode = HASH(ccp->cl_ipaddr);
  738.         ccp->cl_next = Addr_hashtable[hcode];
  739.         Addr_hashtable[hcode] = ccp;
  740.     }
  741. }
  742.  
  743. /*
  744.  * Code to count authentication instances.
  745.  */
  746. #define UIDOFFSET    100000        /* add to a non-uid so it won't
  747.                        conflict with uids        */
  748.  
  749. CountCallAuth(msg)
  750. struct rpc_msg *msg;
  751. {
  752.     int i, len, auth;
  753.     struct passwd *pw;
  754.     unsigned int *oauth;
  755.     static char user_name[16];
  756.  
  757.     auth = msg->ru.RM_cmb.cb_cred.oa_flavor;
  758.  
  759.     if (auth != AUTH_UNIX) {
  760.         auth += UIDOFFSET;
  761.     }
  762.     else {
  763.         /*
  764.          * Convert the opaque authorization into a uid.
  765.          * Should use the XDR decoders.
  766.          */
  767.         oauth = (unsigned int *) msg->ru.RM_cmb.cb_cred.oa_base;
  768.         len = ntohl(oauth[1]);
  769.  
  770.         if ((len % 4) != 0)
  771.             len = len + 4 - len % 4;
  772.  
  773.         auth = ntohl(oauth[2 + len / 4]);
  774.     }
  775.  
  776.     for (i=0; i < nauthcounters; i++) {
  777.         if (auth_counters[i].ac_uid == auth) {
  778.             auth_counters[i].ac_interval++;
  779.             auth_counters[i].ac_total++;
  780.             return;
  781.         }
  782.     }
  783.     
  784.     if (nauthcounters < MAXAUTHS) {
  785.         nauthcounters++;
  786.  
  787.         auth_counters[i].ac_uid = auth;
  788.         auth_counters[i].ac_total = 1;
  789.         auth_counters[i].ac_interval = 1;
  790.  
  791.         switch (auth) {
  792.         case AUTH_NULL + UIDOFFSET:
  793.             auth_counters[i].ac_name = "AUTH_NULL";
  794.             break;
  795.         case AUTH_UNIX + UIDOFFSET:
  796.             auth_counters[i].ac_name = "AUTH_UNIX";
  797.             break;
  798.         case AUTH_SHORT + UIDOFFSET:
  799.             auth_counters[i].ac_name = "AUTH_SHORT";
  800.             break;
  801.         case AUTH_DES + UIDOFFSET:
  802.             auth_counters[i].ac_name = "AUTH_DES";
  803.             break;
  804.         default:
  805.             if ((pw = getpwuid(auth)) != NULL)
  806.                 strcpy(user_name, pw->pw_name);
  807.             else
  808.                 sprintf(user_name, "#%d", auth);
  809.  
  810.             auth_counters[i].ac_name = savestr(user_name);
  811.             break;
  812.         }
  813.  
  814.         sort_auth_counters();
  815.     }
  816. }
  817.  
  818. /*
  819.  * Some code to look at response times.
  820.  */
  821. void
  822. nfs_hash_call(msg, client, tstamp)
  823. struct timeval *tstamp;
  824. struct rpc_msg *msg;
  825. u_long client;
  826. {
  827.     int i;
  828.  
  829.     if (tstamp == NULL)
  830.         return;
  831.  
  832.     for (i=0; i < NFSCALLHASHSIZE; i++) {
  833.         if (nfs_calls[i].used == 0) {
  834.             nfs_calls[i].used = 1;
  835.             nfs_calls[i].proc = msg->rm_call.cb_proc;
  836.             nfs_calls[i].client = client;
  837.             nfs_calls[i].xid = msg->rm_xid;
  838.             nfs_calls[i].time_sec = tstamp->tv_sec;
  839.             nfs_calls[i].time_usec = tstamp->tv_usec;
  840.             return;
  841.         }
  842.     }
  843. }
  844.  
  845. void
  846. nfs_hash_reply(msg, client, tstamp)
  847. struct timeval *tstamp;
  848. struct rpc_msg *msg;
  849. u_long client;
  850. {
  851.     int i;
  852.     double diff;
  853.     u_long proc;
  854.     u_long xid = ntohl(msg->rm_xid);
  855.  
  856.     if (tstamp == NULL)
  857.         return;
  858.  
  859.     for (i=0; i < NFSCALLHASHSIZE; i++) {
  860.         if (nfs_calls[i].used == 0)
  861.             continue;
  862.  
  863.         if (nfs_calls[i].client == client &&
  864.             nfs_calls[i].xid == xid) {
  865.             proc = prc_countmap[nfs_calls[i].proc];
  866.  
  867.             diff = ((tstamp->tv_sec - nfs_calls[i].time_sec) *
  868.                 1000000 +
  869.                 tstamp->tv_usec - nfs_calls[i].time_usec) /
  870.                 1000.0;
  871.  
  872.             prc_counters[proc].pr_complete++;
  873.             prc_counters[proc].pr_response += diff;
  874.             prc_counters[proc].pr_respsqr += diff * diff;
  875.  
  876.             if (diff > prc_counters[proc].pr_maxresp)
  877.                 prc_counters[proc].pr_maxresp = diff;
  878.  
  879.             nfs_calls[i].used = 0;
  880.             return;
  881.         }
  882.     }
  883. }
  884.